﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDSimpleModelGenerator.Common;
using FDSimpleModelGenerator.Entities;
using FDSimpleModelGenerator.Entities.CreateTables;
using FDSimpleModelGenerator.Entities.Enums;
using FDSimpleModelGenerator.IServices;
using Npgsql;

namespace FDSimpleModelGenerator.Services.PostgreSQL
{
    /// <summary>
    /// PostgreSql生成数据库表服务
    /// </summary>
    public class PostgreSqlGenerateTableService : IGenerateTableService
    {
        private readonly IDbAccessor _dbAccessor;
        private readonly IDbConfigResolver _dbConfigResolver;

        public DbType DbType => DbType.PostgreSQL;

        public PostgreSqlGenerateTableService(IDbAccessor dbAccessor, IEnumerable<IDbConfigResolver> dbConfigResolvers)
        {
            _dbAccessor = dbAccessor;
            _dbConfigResolver = dbConfigResolvers.First(r => r.DbType == DbType);
        }

        public GenResult Generate(DbConfig dbConfig, Table tableInfo)
        {
            _dbAccessor.Init(() => new NpgsqlConnection(_dbConfigResolver.GetConnectionString(dbConfig)));

            var sb = new StringBuilder();
            var sbComment = new StringBuilder();
            sb.Append($"--{tableInfo.Description}\r\n");
            if (tableInfo.DeleteExists)
            {
                sb.Append($"DROP TABLE IF EXISTS TABLE \"{tableInfo.Name}\";\r\n");
            }
            sb.Append($"CREATE TABLE \"{tableInfo.Name}\" \r\n");
            sb.Append("(\r\n");
            sbComment.Append($"COMMENT ON TABLE \"{tableInfo.Name}\" IS '{tableInfo.Description}';");
            foreach (var column in tableInfo.Columns)
            {
                sb.Append($"\t{column.Name}{DbDataTypeFormatter.DataType(column.DataType, column.Length, column.Precision)}");
                sb.Append($"{DbDataTypeFormatter.AllowNull(column.AllowNulls)}{DbDataTypeFormatter.DefaultValue(column.DefaultValue, column.DataType)};");

                sbComment.Append($"COMMENT ON COLUMN \"{tableInfo.Name}\".{column.Name} IS '{column.Remark}';\r\n");
            }
            var primaryKeys = tableInfo.Columns.Where(c => c.PrimaryKey).Select(c => c.Name);
            //sb.Append($"{DbDataTypeFormatter.PrimaryKey(primaryKeys)}\r\n");
            DbDataTypeFormatter.CheckAddPrimaryKey(sb, primaryKeys, true);
            sb.Append(");\r\n");
            sb.Append(sbComment);

            if (tableInfo.Indexes.Count() > 0)
            {
                sb.Append("\r\n");
                foreach (var index in tableInfo.Indexes)
                {
                    var columns = index.ToIndexColumns();
                    if (columns.Count() == 0)
                    {
                        continue;
                    }

                    var unique = index.UniqueIndex ? " UNIQUE" : "";
                    sb.Append(
                        $"CREATE{unique} INDEX {DbDataTypeFormatter.IndexName(tableInfo.Name, columns)} ON {tableInfo.Name} {DbDataTypeFormatter.IndexColumns(columns)}\r\n");
                }
            }

            var result = new GenResult { Result = sb.ToString() };
            if (tableInfo.ExecuteSql)
            {
                result.IsExecuteSuccess = _dbAccessor.ExecuteNoneQuery(sb.ToString()) > 0;
            }

            return result;
        }

        public async Task<GenResult> GenerateAsync(DbConfig dbConfig, Table tableInfo)
        {
            return await Task.Run(() => Generate(dbConfig, tableInfo));
        }
    }
}
